/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package JFreeChartExtensions.Collections;


import JFreeChartExtensions.Collections.utils.DatasetSeriesProperties;
import JFreeChartExtensions.Series.XYExtendedIntervalSeries;
import JFreeChartExtensions.Series.XYRegressionSeries;
import JFreeChartExtensions.events.SeriesChangedEvent;
import JFreeChartExtensions.events.SeriesChangedEventType;
import JFreeChartExtensions.listeners.ISeriesChangedListener;
import JFreeChartExtensions.renderers.XYErrorRendererExtended;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.jfree.data.xy.XYIntervalSeries;

/**
 *
 * @author Nobody
 */
public class DatasetCollection implements Cloneable {

    private TreeMap<Integer, XYReggresionSeriesCollection> dataSeriesCollections = new TreeMap<Integer, XYReggresionSeriesCollection>();
    private List<ISeriesChangedListener> listeners = new LinkedList<ISeriesChangedListener>();
    private List<DataRenderersCollection> rendererCollections = new LinkedList<DataRenderersCollection>();
    private int size = 0;

    public int getSize() {
        return size;
    }

    public DataRenderersCollection getMasterRenderer() {
        return rendererCollections.get(0);
    }

    public List<DataRenderersCollection> getMirrorRenderers() {
        return rendererCollections.subList(1, rendererCollections.size());
    }

    public List<DataRenderersCollection> getAllRendererCollections() {
        return rendererCollections;
    }

    public List<ISeriesChangedListener> getSeriesChangedListeners() {
        return listeners;
    }

    public void addSeriesAddedListener(ISeriesChangedListener addedEventListener) {
        listeners.add(addedEventListener);
    }

    public void addSeriesAddedListener(List<ISeriesChangedListener> addedEventListener) {
        listeners.addAll(addedEventListener);
    }

    public void notifyAllChangedListeners(SeriesChangedEvent event) {
        for (ISeriesChangedListener listener : listeners) {
            listener.seriesChanged(event);
        }
    }

    public void addRenderersForSeries(DatasetSeriesProperties datasetSeriesProperties) {
        for (DataRenderersCollection collection : rendererCollections) {
            collection.addRendererForSeries(datasetSeriesProperties);
        }
    }

    public void addSeries(XYIntervalSeries series, int dataset) {
        if (series instanceof XYRegressionSeries) {
            addRegressionSeries(series, dataset);
        } else {
            addSeries(series);
        }
    }

    public void addSeries(XYIntervalSeries series) {
        XYReggresionSeriesCollection collection = new XYReggresionSeriesCollection(size);
        series.setKey(renameIfNeeded((String) series.getKey()));
        collection.addSeries(series);
        upateXYPlots(size, collection);
        dataSeriesCollections.put(size, collection);
        ++size;
        DatasetSeriesProperties datasetSeriesPair = new DatasetSeriesProperties(size - 1, collection.getSeriesCount() - 1, false);
        addRenderersForSeries(datasetSeriesPair);
    }

   /* public void addSeries(ProgressInternalFrame xframe, ProgressInternalFrame yframe, ProgressInternalFrame eframe, int xColumnIdx, int yColumnIdx, int errorColumnIdx, String name, int interval) throws MissingCellValueException {
        addDateSeriesForXYChart(xframe, yframe, eframe, xColumnIdx, yColumnIdx, errorColumnIdx, name, interval);
    }

    public void addSeries(ProgressInternalFrame dataFrame, ProgressInternalFrame errorFrame, int xColumnIdx, int yColumnIdx, List<Integer> rows, String name, int yErrorColumnIdx, List<Integer> errRows, int interval) throws MissingCellValueException {
        XYReggresionSeriesCollection collection = new XYReggresionSeriesCollection(size);
        name = renameIfNeeded(name);
        collection.addDateSeriesForXYChart(dataFrame, errorFrame, xColumnIdx, yColumnIdx, rows, name, yErrorColumnIdx, errRows, interval);
        upateXYPlots(size, collection);
        dataSeriesCollections.put(size++, collection);

        notifyListeners(collection);
    }*/

    private void notifyListeners(XYReggresionSeriesCollection collection) {
        boolean isRegressionSeries = collection.getLastAddedSeries() instanceof XYRegressionSeries;
        DatasetSeriesProperties datasetSeriesPair = new DatasetSeriesProperties(collection.getDatasetNumber(), collection.getSeriesCount() - 1, isRegressionSeries);
        addRenderersForSeries(datasetSeriesPair);
        SeriesChangedEvent seriesChangedEvent = new SeriesChangedEvent(collection.getLastAddedSeries(), SeriesChangedEventType.ADD, datasetSeriesPair);
        notifyAllChangedListeners(seriesChangedEvent);

    }

    public void addRegressionSeries(XYIntervalSeries seriesToRegress, XYExtendedIntervalSeries series) {
        XYReggresionSeriesCollection collection = getCollectionContainingSeries(seriesToRegress);
        collection.addSeries(series);
        notifyListeners(collection);

    }

    public void addRegressionSeries(XYIntervalSeries series, int dataset) {
        XYReggresionSeriesCollection collection = dataSeriesCollections.get(dataset);
        collection.addSeries(series);
        notifyListeners(collection);

    }

    public void removeSeries(String name) {
        XYReggresionSeriesCollection collection = getCollectionContainingSeries(name);
        DatasetSeriesProperties datasetSeriesPair = new DatasetSeriesProperties(collection.getDatasetNumber(), collection.getSeriesIndex(name), false);
        SeriesChangedEvent seriesChangedEvent = new SeriesChangedEvent(collection.getSeries(name), SeriesChangedEventType.ADD, datasetSeriesPair);
        notifyAllChangedListeners(seriesChangedEvent);
        collection.removeSeries(name);
    }

    public int size() {
        return size;
    }

    public List<XYIntervalSeries> getAllNonRegressionSeries() {
        List<XYIntervalSeries> intervalSerieses = new LinkedList<XYIntervalSeries>();
        for (XYReggresionSeriesCollection collection : dataSeriesCollections.values()) {
            intervalSerieses.addAll(collection.getAllNonRegressionSeries());
        }
        return intervalSerieses;
    }

    public XYIntervalSeries getSeriesByName(String name) {
        for (XYReggresionSeriesCollection collection : dataSeriesCollections.values()) {
            for (XYIntervalSeries series : collection.getSeriesList()) {
                if (name.equals(series.getKey())) {
                    return series;
                }
            }
        }
        return null;
    }


    private XYReggresionSeriesCollection getCollectionContainingSeries(String name) {
        for (XYReggresionSeriesCollection collection : dataSeriesCollections.values()) {
            for (XYIntervalSeries series : collection.getSeriesList()) {
                if (name.equals(series.getKey())) {
                    return collection;
                }
            }
        }
        return null;
    }

    private XYReggresionSeriesCollection getCollectionContainingSeries(XYIntervalSeries series) {
        return getCollectionContainingSeries((String) series.getKey());
    }

    private String renameIfNeeded(String name) {
        for (XYReggresionSeriesCollection collection : dataSeriesCollections.values()) {
            for (XYIntervalSeries series : collection.getSeriesList()) {
                if (name.equals(series.getKey())) {
                    name += "_copy";
                }
            }
        }
        return name;
    }

    public TreeMap<Integer, XYReggresionSeriesCollection> getDataSeriesCollections() {
        return dataSeriesCollections;
    }

    public void removeRegressionSeriesInAllCollections() {
        for (XYReggresionSeriesCollection collection : dataSeriesCollections.values()) {
            collection.removeAllRegressionSeries();
        }
    }

    public void addRendererCollection(DataRenderersCollection rendererCollection) {
        this.rendererCollections.add(rendererCollection);
    }

    public void addAll(TreeMap<Integer, XYReggresionSeriesCollection> collection) {
        size = collection.size();
        dataSeriesCollections.putAll(collection);


    }

    private void upateXYPlots(Integer i, XYReggresionSeriesCollection xYReggresionSeriesCollection) {
        for (DataRenderersCollection collection : getAllRendererCollections()) {
            collection.getXyplot().setDataset(i, xYReggresionSeriesCollection);
        }
    }

    public void collectionStructureChanged() {
        for (Entry<Integer, XYReggresionSeriesCollection> entry : dataSeriesCollections.entrySet()) {
            upateXYPlots(entry.getKey(), entry.getValue());
        }
    }

    public void removeSeries(XYIntervalSeries series) {
        removeSeries((String) series.getKey());
    }

    public List<DatasetSeriesProperties> getCordinatesOfAllRegressionSeries() {
        List<DatasetSeriesProperties> datasetSeriesPairs = new LinkedList<DatasetSeriesProperties>();
        for (Entry<Integer, XYReggresionSeriesCollection> entry : dataSeriesCollections.entrySet()) {
            XYReggresionSeriesCollection collection = entry.getValue();
            for (int i = 0; i < collection.getSeriesCount(); ++i) {
                if (collection.getSeries(i) instanceof XYRegressionSeries) {
                    datasetSeriesPairs.add(new DatasetSeriesProperties(entry.getKey(), i, true));
                }
            }
        }
        return datasetSeriesPairs;
    }

/*    public void addDateSeriesForXYChart(ProgressInternalFrame xframe, ProgressInternalFrame yframe, ProgressInternalFrame eframe,
            int xColumnIdx, int yColumnIdx, int errorColumnIdx, String name, int interval) throws MissingCellValueException {


        //  XYReggresionSeriesCollection collection = new XYReggresionSeriesCollection(size);
        name = renameIfNeeded(name);

        //    upateXYPlots(size, collection);
        //   dataSeriesCollections.put(size++, collection);
        //   notifyListeners(collection);




        XYExtendedIntervalSeries xys = new XYExtendedIntervalSeries(name);
        UndoableTableModel xtableModel = (UndoableTableModel) xframe.getDataTable().getModel();
        UndoableTableModel ytableModel = (UndoableTableModel) yframe.getDataTable().getModel();
        UndoableTableModel etableModel = (UndoableTableModel) eframe.getDataTable().getModel();

        boolean lineIgnored = false;
        Integer seriesNumber = 1;

        for (int i = 0; i < xtableModel.getRowCount(); i += interval) {
            Number xCell = xtableModel.getValueAsNumber(i, xColumnIdx);
            Number yCell = ytableModel.getValueAsNumber(i, yColumnIdx);

            if (xCell == null && yCell == null) {
                lineIgnored = true;
                continue;
            } else if (xCell == null || yCell == null) {
                XYReggresionSeriesCollection col = new XYReggresionSeriesCollection(size);
                col.addSeries(xys);
                upateXYPlots(size, col);
                dataSeriesCollections.put(size++, col);
                notifyListeners(col);
                if (xCell == null) {
                    throw new MissingCellValueException("Missing cell value ( {" + xColumnIdx + "}{ " + i + "} )");
                } else if (yCell == null) {
                    throw new MissingCellValueException("Missing cell value ( {" + yColumnIdx + "}{ " + i + "} )");
                }

            }

            if (lineIgnored) {
                if (!xys.isEmpty()) {
                    XYReggresionSeriesCollection col = new XYReggresionSeriesCollection(size);
                    col.addSeries(xys);
                    upateXYPlots(size, col);
                    dataSeriesCollections.put(size++, col);
                    notifyListeners(col);
                }
                xys = new XYExtendedIntervalSeries(name + seriesNumber++);
                lineIgnored = false;
            }

            Float f = xCell.floatValue();
            Float g = yCell.floatValue();
            Float err = (Number) etableModel.getValueAsNumber(i, errorColumnIdx) == null ? 0 : ((Number) etableModel.getValueAsNumber(i, errorColumnIdx)).floatValue();

            xys.add(f.doubleValue(), f.doubleValue(), f.doubleValue(), g.doubleValue(), g.doubleValue() - err.doubleValue(), g.doubleValue() + err.doubleValue());
        }
        XYReggresionSeriesCollection col = new XYReggresionSeriesCollection(size);
        col.addSeries(xys);
        upateXYPlots(size, col);
        dataSeriesCollections.put(size++, col);
        notifyListeners(col);

    }
*/
    public void applyGlobalRendererSettings(int dataset, int seriesIndex, XYErrorRendererExtended errorRenderer) {
        for (DataRenderersCollection collection : rendererCollections) {
            XYErrorRendererExtended errorRendererExtended = collection.getRenderersCollections().get(dataset);
            errorRendererExtended.setSeriesShapesVisible(seriesIndex, errorRenderer.getSeriesShapesVisible(seriesIndex));
            errorRendererExtended.setSeriesLinesVisible(seriesIndex, errorRenderer.getSeriesLinesVisible(seriesIndex));
            errorRendererExtended.setSeriesYError(seriesIndex, errorRenderer.getSeriesYError(seriesIndex));
            errorRendererExtended.setSeriesXError(seriesIndex, false);
            errorRendererExtended.setSeriesPaint(seriesIndex, errorRenderer.getSeriesPaint(seriesIndex));

        }
        notifyAllChangedListeners(new SeriesChangedEvent(getDataSeriesCollections().get(dataset).getSeries(seriesIndex), SeriesChangedEventType.UPDATE, null));
    }

    public void addRegressionSeriesCollection(XYReggresionSeriesCollection col) {
        upateXYPlots(size, col);
        dataSeriesCollections.put(size++, col);
        notifyListeners(col);

    }

    public Iterable<XYIntervalSeries> getSeriesList() {
        List<XYIntervalSeries> seriesList = new ArrayList<XYIntervalSeries>();
        for (Entry<Integer, XYReggresionSeriesCollection> entry : getDataSeriesCollections().entrySet()) {
           XYReggresionSeriesCollection seriesCollection =  entry.getValue();
           seriesList.addAll(seriesCollection.getSeriesList());
        }
        return seriesList;
    }
}
